package labb1.fordjupn;

import labb1.del2.Card;
import labb1.del2.Deck;

/**
 * @author Mikko Puustinen (mikko.puustinen@gmail.com)
 * @version 0.1, 2007-nov-02
 */
public abstract class GameFactory {
    private PlayerFactory playerFactory;
    private boolean isRunning;
    private int currentPlayer;
    private Deck deck;

    /**
     * Creates a Game.
     *
     * @param playerFactory the PlayerFactory to use which will supply the game
     *                      with all the Players, and so on.
     */
    public GameFactory(PlayerFactory playerFactory) {
        this.playerFactory = playerFactory;
        isRunning = true;
        currentPlayer = 0;
        deck = new Deck();
        initializeGame();
    }

    /**
     * Initializes the game, i.e. hands out cards to all Players.
     */
    private void initializeGame() {
        for (Player p : playerFactory.getAllPlayers()) {
            p.resetPlayer();
            for (int i = 0; i < 4; i++) {
                p.addCard(deck.getCard());
            }
        }
    }

    /**
     * Returns the object of the current Player.
     *
     * @return the object of the current Player.
     */
    public Player getCurrentPlayer() {
        return playerFactory.getPlayerAt(currentPlayer);
    }

    /**
     * Checks if the actual player is a ComputerPlayer.
     *
     * @return true if the Player is a ComputerPlayer, false otherwise.
     */
    public boolean isActivePlayerComputer() {
        return getCurrentPlayer() instanceof ComputerPlayer;
    }

    /**
     * Changes the active player.
     */
    public void nextPlayer() {
        if ((currentPlayer + 1) >= playerFactory.numberOfPlayers()) {
            currentPlayer = 0;
        } else {
            ++currentPlayer;
        }
    }

    /**
     * Get the index of the actual player.
     *
     * @return the index of the Player.
     */
    public int getIndexOfCurrentPlayer() {
        return currentPlayer;
    }

    /**
     * Get the status of the playerFactory.
     *
     * @return true if the playerFactory is active, i.e. the Deck has still
     *         cards in it, false if the playerFactory has ended (with a
     *         winner).
     */
    public boolean isRunning() {
        return isRunning;
    }

    /**
     * If the playerFactory has enough players to start the playerFactory. In
     * this case the playerFactory needs at least 2 Players.
     *
     * @return true if the playerFactory is ready to start, false otherwise.
     */
    public boolean isReadyToPlay() {
        return playerFactory.numberOfPlayers() >= 2;
    }

    /**
     * Checks if the chosen opponent has a Card with the specified value. If it
     * has this the Card will be moved to the current Player.
     *
     * @param opponentIndex the index of the opponent.
     * @param cardValue     the value to check for.
     *
     * @return true if the value was found, false otherwise.
     */
    public boolean hasOpponentValue(int opponentIndex, int cardValue) {
        Player opponent = playerFactory.getPlayerAt(opponentIndex);
        Player current = getCurrentPlayer();
        boolean isFound = false;

        if (opponent.numberOfSameValues(cardValue) > 0) {
            int i = 0;
            for (Card c : opponent.getAllCards()) {
                if (c.getValue() == cardValue) {
                    current.addCard(opponent.getCard(i));
                    isFound = true;
                } else {
                    i++;
                }
            }
        }

        if (isFound && opponent.getNoOfCard() == 0) {
            takeCardFromDeck(opponentIndex);
        }

        return isFound;
    }

    /**
     * Moves a Card from the sea (the main Deck of Cards) to the current Player.
     * If the Deck is empty after the operation the game has finished. This
     * means that the isRunnings() will return FALSE.
     *
     * @param index index of the player to add the card to.
     */
    public void takeCardFromDeck(int index) {
        if (deck.getNoOfCards() == 0) {
            isRunning = false;
            Player[] winner = new Player[playerFactory.numberOfPlayers()];
            int max = -1;
            int i = 0;
            for (Player pl : playerFactory.getAllPlayers()) {
                if (pl.getScore() > 0) {
                    if (pl.getScore() > max) {
                        max = pl.getScore();
                        for (int j = 0; j < winner.length; j++)
                            winner[j] = null;
                        i = 0;
                        winner[i++] = pl;
                    } else if (pl.getScore() == max) {
                        winner[i++] = pl;
                    }
                }
            }
            if (i > 0) {
                for (Player p : winner) {
                    if (p == null) {

                    } else {
                        p.addWonGame();
                    }
                }
            }
        } else {
            Player p = playerFactory.getPlayerAt(index);
            Card c = deck.getCard();
            p.addCard(c);
        }
    }
}
